<?php
/**
 * DBShop 电子商务系统
 *
 * ==========================================================================
 * @link      https://www.dbshop.net/
 * @copyright 北京珑大钜商科技有限公司，并保留所有权利。
 * @license   https://www.dbshop.net/license.html License
 * ==========================================================================
 *
 * @author    静静的风 <baron@loongdom.cn>
 *
 */

namespace Admin\Data;

use Laminas\Config\Factory;
use Laminas\Config\Writer\PhpArray;
use Laminas\Crypt\Password\Bcrypt;
use Laminas\Filter\Decompress;
use Laminas\Json\Json;
use Laminas\Math\Rand;
use Laminas\Mvc\I18n\Translator;
use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumberUtil;
use PluginAliOss\Common\AliOssCommon;
use PluginCdnImageSpeed\Common\ImageSpeedCommon;
use PluginQiniuKodo\Common\QiniuKodoCommon;
use PluginTencentCos\Common\TencentCosCommon;

class Common
{

    const ORDER_CANCEL_ORDER                = 0;    //取消订单
    const ORDER_WAIT_PAYMENT                = 10;   //待付款
    const ORDER_WAIT_GOODS_ARRIVE           = 19;   //等待预售商品到货
    const ORDER_FINISH_PAYMENT              = 20;   //已付款
    const ORDER_DISTRIBUTION_GOODS          = 30;   //正在配货
    const ORDER_WAIT_MOVE_WAREHOUSE         = 35;   //等待移仓
    const ORDER_MOVE_WAREHOUSE              = 38;   //正在移仓
    const ORDER_FINISH_DISTRIBUTION_GOODS   = 40;   //已配货
    const ORDER_GOODS_SHIPPED               = 50;   //已发货
    const ORDER_GOODS_RECEIVED              = 60;   //已收货
    const ORDER_COMPLETE                    = 80;   //交易完成

    //支持支付原路退回的支付名称(payCode)
    const REFUND_PAYMENT_ARRAY = ['Alipay' => 'Alipay', 'Wxpay' => 'Wxpay', 'BalancePay' => 'BalancePay'];

    /**
     * 当前文件内部赋值使用的值
     * @var array
     */
    private static $commonData = [];

    /**
     * 生成的配置文件的后缀名
     * @var string
     */
    private static $configFileSuffix = '.php';

    /**
     * 状态(通用)
     * @param Translator $translator
     * @param int $style
     * @return array
     */
    public static function state(Translator $translator, int $style = 1)
    {
        return [
            1 => $translator->translate('启用'),
            0 => $style == 1 ? $translator->translate('禁用') : '<label class="text-red">'. $translator->translate('禁用') .'</label>'];
    }

    /**
     * 是、否 通用状态
     * @param Translator $translator
     * @return array
     */
    public static function generalState(Translator $translator)
    {
        return [0 => $translator->translate('否'), 1 => $translator->translate('是')];
    }

    /**
     * 提现状态
     * @param Translator $translator
     * @return array
     */
    public static function withdrawState(Translator $translator)
    {
        return [1 => $translator->translate('处理中'), 2 => $translator->translate('提现完成'), 3 => $translator->translate('拒绝提现')];
    }

    /**
     * 邮件服务器类型
     * @param Translator $translator
     * @return array
     */
    public static function emailServiceType(Translator $translator)
    {
        return [
            'smtpService'       => $translator->translate('SMTP邮件服务器'),
            'dbshopEmailService'=> $translator->translate('珑大官方邮件服务')
        ];
    }

    /**
     * 注册会员验证方式
     * @param Translator $translator
     * @return array
     */
    public static function userAuditType(Translator $translator)
    {
        return [
            'no'    => $translator->translate('无验证'),
            'email' => $translator->translate('邮箱验证'),
            'audit' => $translator->translate('人工验证')
        ];
    }

    /**
     * 商品类型
     * @param Translator $translator
     * @param int $style
     * @return array
     */
    public static function goodsType(Translator $translator, int $style = 1)
    {
        return [
            1 => $translator->translate('实物商品'),
            2 => $translator->translate('虚拟商品')
        ];
    }

    /**
     * 积分类型
     * @param Translator $translator
     * @return array
     */
    public static function integralType(Translator $translator)
    {
        return [
            1 => $translator->translate('消费积分'),
            2 => $translator->translate('等级积分')
        ];
    }

    /**
     * 余额操作类型
     * @param Translator $translator
     * @return array
     */
    public static function balanceChangeType(Translator $translator)
    {
        return [
            1 => $translator->translate('后台操作'),
            2 => $translator->translate('客户充值'),
            3 => $translator->translate('客户提现'),
            4 => $translator->translate('订单付款'),
            5 => $translator->translate('售后退款'),
            6 => $translator->translate('充值码充值'),
            7 => $translator->translate('分销佣金'),
            8 => $translator->translate('提现手续费'),
            9 => $translator->translate('取消订单退款'),
        ];
    }

    /**
     * 增加与减少，通用类型
     * @param Translator $translator
     * @param int $style
     * @return array
     */
    public static function changeType(Translator $translator, int $style = 1)
    {
        return [
            '+' => $translator->translate('增加'),
            '-' => $translator->translate('减少')
        ];
    }

    /**
     * 商品优惠客户组范围显示
     * @param Translator $translator
     * @return array
     */
    public static function goodsDiscountUserGroupType(Translator $translator)
    {
        return [
            'allUser'   => $translator->translate('全部客户组'),
            'userGroup' => $translator->translate('个别客户组')
        ];
    }

    /**
     * 虚拟商品，内容的三种形式
     * @param Translator $translator
     * @return array
     */
    public static function virtualGoodsType(Translator $translator)
    {
        return [
            1 => $translator->translate('手动添加'),
            2 => $translator->translate('自动生成'),
            3 => $translator->translate('自动重复')
        ];
    }

    /**
     * 虚拟商品状态
     * @param Translator $translator
     * @return array
     */
    public static function virtualGoodsState(Translator $translator)
    {
        return [
            1 => $translator->translate('未交易'),
            2 => $translator->translate('已交易'),
            3 => $translator->translate('已过期')
        ];
    }

    /**
     * 有货显示
     * @param Translator $translator
     * @param int $style
     * @return array
     */
    public static function goodsStockShow(Translator $translator, int $style = 1)
    {
        return [
            1 => $translator->translate('有货')
        ];
    }

    /**
     * 缺货显示
     * @param Translator $translator
     * @param int $style
     * @return array
     */
    public static function goodsOutStockShow(Translator $translator, int $style = 1)
    {
        return [
            1 => $translator->translate('缺货')
        ];
    }

    /**
     * 商品状态
     * @param Translator $translator
     * @param int $style
     * @return array
     */
    public static function goodsState(Translator $translator, int $style = 1)
    {
        return [
            1 => $translator->translate('上架'),
            2 => $style == 1 ? $translator->translate('下架') : '<label class="text-red">'. $translator->translate('下架') .'</label>'
        ];
    }

    /**
     * 微信登录的类型数组
     * @return string[]
     */
    public static function wechatLoginTypeArray()
    {
        return [
            'wechat',       //微信内登录
            'wechatScan',   //微信pc网站登录
            'wechatMini',   //微信小程序登录
            'wechatApp'     //微信app登录
        ];
    }

    /**
     * 第三方登录名称
     * @param Translator $translator
     * @return array
     */
    public static function otherLoginTextName(Translator $translator)
    {
        return [
            'wechat'    => $translator->translate('微信'),
            'wechatScan'=> $translator->translate('微信扫码'),
            'qq'        => $translator->translate('QQ'),
            'alipay'    => $translator->translate('支付宝'),
            'google'    => 'Google',
            'facebook'  => 'Facebook',
            'twitter'   => 'twitter'
        ];
    }

    /**
     * 第三方登录标记数组
     * @return string[]
     */
    public static function otherLoginTypeArray()
    {
        return [
            'weixin_login_state'    => 'wechat',
            'weixin_web_login_state'=> 'wechatScan',
            'qq_login_state'        => 'qq',
            'alipay_login_state'    => 'alipay',
            'google_login_state'    => 'google',
            'facebook_login_state'  => 'facebook',
            'twitter_login_state'   => 'twitter'
        ];
    }

    /**
     * 会员状态
     * @param Translator $translator
     * @param int $style
     * @return array
     */
    public static function userStatus(Translator $translator, int $style = 1)
    {
        return [
            1 => $translator->translate('开启'),
            2 => $translator->translate('关闭'),
            3 => $translator->translate('待审核')
        ];
    }

    /**
     * 支付状态
     * @param Translator $translator
     * @return array
     */
    public static function payStatus(Translator $translator)
    {
        return [
            10 => $translator->translate('未支付'),
            20 => $translator->translate('支付完成')
        ];
    }

    /**
     * 支付方式显示范围
     * @param Translator $translator
     * @return array
     */
    public static function paymentShowArea(Translator $translator)
    {
        return [
            'pc'    => $translator->translate('电脑端显示'),
            'phone' => $translator->translate('手机端显示'),
        ];
    }

    /**
     * 验证方式
     * @param Translator $translator
     * @param $typeArray
     * @return array
     */
    public static function verificationArray(Translator $translator, $typeArray)
    {
        $array['no'] = $translator->translate('无需验证');
        if (in_array('email', $typeArray)) $array['emailCode'] = $translator->translate('邮箱验证码验证');
        if (in_array('phone', $typeArray)) $array['phoneCode'] = $translator->translate('手机验证码验证');

        return $array;
    }

    /**
     * 订单状态范围
     * @param $translator
     * @return array
     */
    public static function orderStatus($translator)
    {
        return [
            self::ORDER_CANCEL_ORDER                => $translator->translate('取消订单'),
            self::ORDER_WAIT_PAYMENT                => $translator->translate('待付款'),
            self::ORDER_WAIT_GOODS_ARRIVE           => $translator->translate('等待支付尾款'),
            self::ORDER_FINISH_PAYMENT              => $translator->translate('已付款'),
            self::ORDER_DISTRIBUTION_GOODS          => $translator->translate('正在配货'),
            self::ORDER_WAIT_MOVE_WAREHOUSE         => $translator->translate('等待移仓'),
            self::ORDER_MOVE_WAREHOUSE              => $translator->translate('正在移仓'),
            self::ORDER_FINISH_DISTRIBUTION_GOODS   => $translator->translate('已配货'),
            self::ORDER_GOODS_SHIPPED               => $translator->translate('已发货'),
            self::ORDER_GOODS_RECEIVED              => $translator->translate('已收货'),
            self::ORDER_COMPLETE                    => $translator->translate('交易完成')
        ];
    }

    /**
     * 单独获取订单状态的编码
     * @param $statusStr
     * @return mixed
     */
    public static function orderStatusCode($statusStr)
    {
        return constant('self::ORDER_'.strtoupper($statusStr));
    }

    /**
     * 退货类型
     * @param Translator $translator
     * @return array
     */
    public static function orderGoodsReturnType(Translator $translator)
    {
        return [
            1   => $translator->translate('退货退款'),
            2   => $translator->translate('退款(不退货)'),
            3   => $translator->translate('换货')
        ];
    }

    /**
     * 订单退款类型，包括售后退款
     * @param Translator $translator
     * @return array
     */
    public static function orderRefundType(Translator $translator)
    {
        return [
            1   => $translator->translate('商品售后-退货退款'),
            2   => $translator->translate('商品售后-退款(不退货)'),
            4   => $translator->translate('订单取消-退款'),
        ];
    }

    /**
     * 退换货状态
     * @param Translator $translator
     * @return array
     */
    public static function orderGoodsReturnState(Translator $translator)
    {
        return [
            1   => $translator->translate('等待审核'),
            2   => $translator->translate('审核通过'),
            3   => $translator->translate('驳回申请')
        ];
    }

    /**
     * 退款支付方式
     * @param Translator $translator
     * @param string|null $paymentCode
     * @param string|null $outTradeNo
     * @return array
     */
    public static function goodsReturnPayType(Translator $translator, string $paymentCode = null, string $outTradeNo = null)
    {
        if (!empty($paymentCode) && in_array($paymentCode, self::REFUND_PAYMENT_ARRAY) && $paymentCode != 'BalancePay') {
            $paymentConfig = self::getPaymentConfig($paymentCode);
            if (!empty($outTradeNo) && isset($paymentConfig['originalRefundState']['checked']) && $paymentConfig['originalRefundState']['checked'] == 1 && $paymentConfig['paymentState']['checked'] == 1) return ['balancePay' => $translator->translate('退款到余额'), 'originalPay' => $translator->translate('原路退款到支付账户')];
        }

        return [
            'balancePay'=> $translator->translate('退款到余额'),
            'otherPay'  => $translator->translate('退款到银行或第三方支付')
        ];
    }

    /**
     * 退款支付方式数组
     * @param Translator $translator
     * @return array
     */
    public static function goodsReturnPayTypeArray(Translator $translator)
    {
        return [
            'balancePay'    => $translator->translate('退款到余额'),
            'otherPay'      => $translator->translate('退款到银行或第三方支付'),
            'originalPay'   => $translator->translate('原路退款到支付账户')
        ];
    }

    /**
     * 支付类型数组
     * @param Translator $translator
     * @return array
     */
    public static function paymentArray(Translator $translator)
    {
        return [
            'OnlinePay'     => $translator->translate('在线支付'),
            'CashOnDelivery'=> $translator->translate('货到付款'),
            'OfflinePay'    => $translator->translate('线下付款'),
        ];
    }

    /**
     * 支付类型，OnlinePay 在线支付、OfflinePay 线下付款、CashOnDelivery 货到付款(当订单全部为虚拟商品时，不显示货到付款)
     * @param false $virtualGoods true 全部是虚拟商品，false 部分是虚拟商品
     * @param false $haveGoodsVirtual true 商品中有虚拟商品，false 商品中无虚拟商品
     * @param string $deliveryType self-fetch 为自提点提货
     * @return array
     */
    public static function paymentType(bool $virtualGoods = false, bool $haveGoodsVirtual = false, string $deliveryType = '')
    {
        $paymentType[] = 'OnlinePay';

        if($deliveryType != 'self-fetch') {
            if (
                !$virtualGoods
                && !$haveGoodsVirtual
                && self::getPaymentConfig('CashOnDelivery')['paymentState']['checked'] == 1
                && self::readConfigFile('delivery')['cashOnDelivery'] == 1
            ) {
                $paymentType[] = 'CashOnDelivery';
            }
        }

        if (self::getPaymentConfig('OfflinePay')['paymentState']['checked'] == 1) $paymentType[] = 'OfflinePay';

        return $paymentType;
    }

    /**
     * 支付类型名称
     * @param $typeCode
     * @param Translator $translator
     * @return mixed
     */
    public static function paymentTypeName($typeCode, Translator $translator)
    {
        $paymentTypeArray = self::paymentArray($translator);
        return $paymentTypeArray[$typeCode];
    }

    /**
     * 配送类型数组
     * @param Translator $translator
     * @return array
     */
    public static function deliveryArray(Translator $translator)
    {
        return [
            'autoDelivery'  => $translator->translate('自动发货'),
            'delivery'      => $translator->translate('商家配送'),
            'selfFetch'     => $translator->translate('到店自提')
        ];
    }

    /**
     * 配送类型，delivery 商家配送、selfFetch 到店自提、autoDelivery 自动发货（当商品全部为虚拟商品时，显示自动发货）
     * @param false $virtualGoods  true 全部是虚拟商品，false 部分是虚拟商品
     * @param false $haveGoodsVirtual  true 商品中有虚拟商品，false 商品中无虚拟商品
     * @return string[]
     */
    public static function deliveryType(bool $virtualGoods = false, bool $haveGoodsVirtual = false)
    {
        return $virtualGoods ? ['autoDelivery'] : ($haveGoodsVirtual ? ['delivery'] : ['delivery', 'selfFetch']);
    }

    /**
     * 配送类型名称
     * @param $typeCode
     * @param Translator $translator
     * @return mixed
     */
    public static function deliveryTypeName($typeCode, Translator $translator)
    {
        $deliveryTypeArray = self::deliveryArray($translator);
        return $deliveryTypeArray[$typeCode];
    }

    /**
     * 配送模式
     * @param Translator $translator
     * @return array
     */
    public static function deliveryMode(Translator $translator)
    {
        return [1 => $translator->translate('统一配送'), 2 => $translator->translate('单独配送')];
    }

    /**
     * 手机短信服务商
     * @param Translator $translator
     * @return array
     */
    public static function smsServiceProvider(Translator $translator)
    {
        return [
            'huyiSms'   => $translator->translate('互亿无线短信'),
            'aliSms'    => $translator->translate('阿里云短信'),
            'tencentSms'=> $translator->translate('腾讯云短信'),
        ];
    }

    /**
     * 管理员接收短信的提醒类型
     * @param Translator $translator
     * @return array
     */
    public static function adminReceivePhoneMessage(Translator $translator)
    {
        return [
            'addOrder'      => $translator->translate('订单提交'),
            'paymentOrder'  => $translator->translate('订单付款'),
            'shipOrder'     => $translator->translate('订单发货'),
            'receiptOrder'  => $translator->translate('订单收货'),
            'cancelOrder'   => $translator->translate('订单取消')
        ];
    }

    /**
     * 图片上传类型
     * @return array
     */
    public static function imageType()
    {
        return [
            'image/jpeg,image/pjpeg' => 'jpg',
            'image/gif' => 'gif',
            'image/png,image/x-png' => 'png',
            'image/bmp,image/x-ms-bmp,image/x-windows-bmp' => 'bmp',
            'image/x-ico,image/x-icon,image/vnd.microsoft.icon' => 'ico'
        ];
    }

    /**
     * 图片裁切方式
     * @param Translator $translator
     * @return array
     */
    public static function imageCrop(Translator $translator)
    {
        return ['inset' => $translator->translate('自适应裁切'), 'outbound' => $translator->translate('绝对裁切')];
    }

    /**
     * 图片命名方式
     * @param Translator $translator
     * @return array
     */
    public static function imageRenameType(Translator $translator)
    {
        return ['original' => $translator->translate('图片原始名称'), 'random' => $translator->translate('图片随机命名')];
    }

    /**
     * 水印类型
     * @param Translator $translator
     * @return array
     */
    public static function watermarkType(Translator $translator)
    {
        return ['image' => $translator->translate('图片'), 'text' => $translator->translate('文字')];
    }

    /**
     * scheme
     * @return array
     */
    public static function urlScheme()
    {
        return ['http://' => 'http://', 'https://' => 'https://'];
    }

    /**
     * 水印图片位置
     * @param Translator $translator
     * @return array
     */
    public static function watermarkLocation(Translator $translator)
    {
        return [
            '1' => $translator->translate('顶部居左'),
            '2' => $translator->translate('顶部居中'),
            '3' => $translator->translate('顶部居右'),
            '4' => $translator->translate('中部居左'),
            '5' => $translator->translate('中部居中'),
            '6' => $translator->translate('中部居右'),
            '7' => $translator->translate('底部居左'),
            '8' => $translator->translate('底部居中'),
            '9' => $translator->translate('底部居右')
        ];
    }

    /**
     * 前台会员组价格显示类型
     * @param Translator $translator
     * @return array
     */
    public static function userGroupPriceType(Translator $translator)
    {
        return [1 => $translator->translate('显示全部会员组价格'), 0 => $translator->translate('显示当前会员组价格')];
    }

    /**
     * SMTP安全连接
     * @param Translator $translator
     * @return array
     */
    public static function smtpSecureConn(Translator $translator)
    {
        return ['no' => $translator->translate('无'), 'SSL' => 'SSL', 'TLS' => 'TLS'];
    }

    /**
     * 货到付款状态
     * @param Translator $translator
     * @return array
     */
    public static function cashOnDeliveryState(Translator $translator)
    {
        return [2 => $translator->translate('不支持'), 1 => $translator->translate('支持')];
    }

    /**
     * 获取配送轨迹接口类型
     * @return array|\Laminas\Config\Config
     */
    public static function deliveryApiType()
    {
        return Factory::fromFile('data/moduleData/System/ShopDelivery/deliveryApiType.php');
    }

    /**
     * 配送公司的动态绑定列表
     * @param $typeName
     * @return array|\Laminas\Config\Config
     */
    public static function deliveryApiCompanyCode($typeName)
    {
        $file = 'data/moduleData/System/ShopDelivery/ApiExpressCompany/'.basename($typeName).'ApiCompany.php';
        if(file_exists($file)) return Factory::fromFile($file);
        return [];
    }

    public static function deliverySet(Translator $translator)
    {
        return ['T' => $translator->translate('统一设置'), 'G' => $translator->translate('个性化地区设置')];
    }

    /**
     * 商品属性类型
     * @param Translator $translator
     * @return array
     */
    public static function goodsAttributeType(Translator $translator)
    {
        return [
            'input'     => $translator->translate('单行表单'),
            'textarea'  => $translator->translate('文本域'),
            'select'    => $translator->translate('下拉'),
            'radio'     => $translator->translate('单选'),
            'checkbox'  => $translator->translate('多选')
            ];
    }

    /**
     * 客户性别
     * @param Translator $translator
     * @return array
     */
    public static function userSex(Translator $translator)
    {
        return [
            3 => $translator->translate('保密'),
            1 => $translator->translate('男'),
            2 => $translator->translate('女')
        ];
    }

    /**
     * 重量单位
     * @param Translator $translator
     * @return array
     */
    public static function weightUnit(Translator $translator)
    {
        return [
            '1|克'       => $translator->translate('克'),
            '1000|千克'  => $translator->translate('千克'),
            '50|两'      => $translator->translate('两'),
            '500|斤'     => $translator->translate('斤'),
            '1000|公斤'  => $translator->translate('公斤')
        ];
    }

    /**
     * 体积单位
     * @param Translator $translator
     * @return array
     */
    public static function volumeUnit(Translator $translator)
    {
        return [];
    }

    /**
     * 管理员密码生成
     * @param $password
     * @return string
     */
    public static function createAdminPassword($password)
    {
        $bcPassword = new Bcrypt();
        return $bcPassword->create($password);
    }

    /**
     * 验证管理员密码
     * @param $password
     * @param $adminPassword
     * @return bool
     */
    public static function verifyAdminPassword($password, $adminPassword)
    {
        $bcPassword = new Bcrypt();
        return $bcPassword->verify($password, $adminPassword);
    }

    /**
     * 客户密码生成
     * @param $password
     * @return string
     */
    public static function createUserPassword($password)
    {
        $bcPassword = new Bcrypt();
        return $bcPassword->create($password);
    }

    /**
     * 验证客户密码
     * @param $password
     * @param $userPassword
     * @return bool
     */
    public static function verifyUserPassword($password, $userPassword)
    {
        $bcPassword = new Bcrypt();
        return $bcPassword->verify($password, $userPassword);
    }

    /**
     * 余额支付密码生成
     * @param $password
     * @return string|null
     */
    public static function createPayPassword($password)
    {
        $bcPassword = new Bcrypt();
        return empty($password) ? null : $bcPassword->create($password);
    }

    /**
     * 验证余额支付密码
     * @param $password
     * @param $payPassword
     * @return bool
     */
    public static function verifyPayPassword($password, $payPassword)
    {
        $bcPassword = new Bcrypt();
        return $bcPassword->verify($password, $payPassword);
    }

    /*=========================================配置文件及opcache处理=========================================*/
    /**
     * 配置文件生成方法
     * @param $key
     * @param array $data
     * @return bool
     */
    public static function writeConfigFile($key, array $data)
    {
        $writeFile = new PhpArray();
        $writeFile->setUseBracketArraySyntax(true);

        $configFile = self::configFile($key);
        $writeFile->toFile($configFile, $data);

        //如配置文件是php文件且开启了opcache 则设置该缓存失效
        if(self::$configFileSuffix == '.php') self::opcacheInvalidate($configFile);

        return true;
    }

    /**
     * 配置文件读取方法
     * @param $key
     * @return array|mixed|\Laminas\Config\Config
     */
    public static function readConfigFile($key)
    {
        if(self::$configFileSuffix == '.php') {
            $includeFile = self::configFile($key);
            if (file_exists($includeFile)) return include $includeFile;
            return [];
        }

        return Factory::fromFile(self::configFile($key));
    }

    /**
     * 配置文件路径
     * @param $key
     * @return string
     */
    private static function configFile($key)
    {
        $fileArray = [
            'config'    => 'data/moduleData/System/shopConfig',     //系统配置
            'dbshopService'=> 'data/moduleData/System/dbshopService',//dbshop服务调用
            'upload'    => 'data/moduleData/System/uploadConfig',   //附件配置
            'currency'  => 'data/moduleData/System/currencyConfig', //货币配置
            'template'  => 'data/moduleData/System/template',       //模板配置
            'customer'  => 'data/moduleData/System/customer',       //客户配置
            'phoneArea' => 'data/moduleData/System/phoneArea',      //国际电话区号
            'language'  => 'data/moduleData/System/language',       //系统可用语言包
            'integral'  => 'data/moduleData/User/integral',         //积分类型
            'integralRule'  => 'data/moduleData/User/integralRule', //积分规则
            'userGroup' => 'data/moduleData/User/userGroup',        //启用等级积分的客户组
            'delivery'  => 'data/moduleData/System/shopDelivery',   //商家配送设置
            'emailMessage'  => 'data/moduleData/System/MessageNotification/emailMessage',   //电邮提醒设置
            'phoneMessage'  => 'data/moduleData/System/MessageNotification/phoneMessage',   //手机短信提醒设置
            'discountRule'  => 'data/moduleData/Operation/discountRule',//促销规则
            'coupon'    => 'data/moduleData/Operation/coupon',      //优惠券
            'onlineService' => 'data/moduleData/Extend/online/onlineService',//在线客服

            'pluginModule'  => 'data/moduleData/Plugin/plugin.module',//插件的module
            'moduleExtend'  => 'data/moduleExtend',//将插件动态注册
            'topMenu'       => 'data/moduleData/Plugin/topSiteUrl'
        ];
        return $fileArray[$key] . self::$configFileSuffix;
    }

    /**
     * 单个配置信息获取获取
     * @param $configKey
     * @param string $typeConfig
     * @return mixed|string[]|null
     */
    public static function configValue($configKey, string $typeConfig = 'upload')
    {
        $config = self::readConfigFile($typeConfig);

        if($configKey == 'upload_image_max') {//图片上传大小限制
            return ['min' => '1kB', 'max' => number_format($config[$configKey]/1024, 2) . 'MB'];
        }

        return isset($config[$configKey]) ? $config[$configKey] : null;
    }

    /**
     * 获取dbshop.json并解析
     * @param string $strName
     * @return array|\Laminas\Config\Config|mixed|string
     */
    public static function dbshopJson(string $strName = '')
    {
        $file = 'data/moduleData/System/dbshop.json';
        if (file_exists($file)) {
            $dbshop = Factory::fromFile($file);
            if (!empty($strName)) return $dbshop[$strName]??'';
            else return $dbshop;
        }
        return !empty($strName) ? '' : [];
    }

    /**
     * 获取opcache状态信息
     * @param $sign
     * @return bool|mixed
     */
    public static function opcacheStatus($sign)
    {
        if(function_exists('opcache_get_status')) {
            $status = opcache_get_status();
            if(isset($status[$sign])) return $status[$sign];
        }
        return false;
    }

    /**
     * 重置或清除整个字节码缓存数据
     * @return bool
     */
    public static function opcacheReset()
    {
        if(self::opcacheStatus('opcache_enabled') && function_exists('opcache_reset')) return opcache_reset();
        return false;
    }

    /**
     * 指定某脚本文件字节码缓存失效
     * @param $script
     * @return bool
     */
    public static function opcacheInvalidate($script)
    {
        if(self::opcacheStatus('opcache_enabled') && function_exists('opcache_invalidate')) {
            return opcache_invalidate($script, true);
        }
        return false;
    }

    /**
     * 无需运行，就可以编译并缓存脚本
     * 该方法可以用于在不用运行某个 PHP 脚本的情况下，编译该 PHP 脚本并将其添加到字节码缓存中去。 该函数可用于在 Web 服务器重启之后初始化缓存，以供后续请求调用。
     * @param $file
     * @return bool
     */
    public static function opcacheCompile($file)
    {
        if(self::opcacheStatus('opcache_enabled') && function_exists('opcache_compile_file')) return opcache_compile_file($file);
        return false;
    }
    /*=========================================配置文件及opcache处理=========================================*/
    /**
     * 对图片进行云存储地址转换，type 类型包括 goods goodsBrand goodsClass ad avatar
     * @param $image
     * @param $type
     * @return mixed|string
     */
    public static function shopImageOss($image, $type)
    {
        if (class_exists(AliOssCommon::class)) {
            return AliOssCommon::imageUrl($image, $type);
        }
        if (class_exists(TencentCosCommon::class)) {
            return TencentCosCommon::imageUrl($image, $type);
        }
        if (class_exists(QiniuKodoCommon::class)) {
            return QiniuKodoCommon::imageUrl($image, $type);
        }

        return $image;
    }

    /**
     * 云存储指定列表
     * @param $dir
     * @param $type
     * @return array
     * @throws \Exception
     */
    public static function ossImageList($dir, $type)
    {
        if (class_exists(AliOssCommon::class)) {
            return AliOssCommon::ossImageList(AliOssCommon::ossConfig(), $dir, $type);
        }
        if (class_exists(TencentCosCommon::class)) {
            return TencentCosCommon::cosImageList(TencentCosCommon::cosConfig(), $dir, $type);
        }
        if (class_exists(QiniuKodoCommon::class)) {
            return QiniuKodoCommon::kodoImageList(QiniuKodoCommon::ossConfig(), $dir, $type);
        }
        return [];
    }

    /**
     * 对图片进行加速优化处理，type 类型包括 goods goodsBrand goodsClass ad avatar
     * @param $image
     * @param $type
     * @return mixed
     */
    public static function shopImageSpeed($image, $type)
    {
        if (class_exists(ImageSpeedCommon::class)) {
            return ImageSpeedCommon::cdnImage($image, $type);
        }
        return $image;
    }

    /**
     * 商城前台内容处理，目前包含cdn处理
     * @param $body
     * @param $type
     * @return string|string[]|null
     */
    public static function shopBody($body, $type)
    {
        $imageList  = self::bodyImageArray($body);

        if ($imageList) {
            $patterns       = [];
            $replacements   = [];
            foreach ($imageList as $value) {
                if (stripos($value, 'http') === false) {
                    $imageL = self::shopImageOss($value, $type);
                    if ($imageL == $value) $imageL = self::shopImageSpeed($value, $type);
                    if ($value != $imageL) {
                        $replacements[] = $imageL;
                        $patterns[] = "/" . preg_replace("/\//i","\/", $value) . "/";
                    }
                }
            }
            if (!empty($replacements)) return preg_replace($patterns, $replacements, $body);
        }

        return $body;
    }

    /**
     * api前台内容处理，将相对路径的图片转换为url地址
     * @param $body
     * @param $type
     * @param $url
     * @return array|mixed|string|string[]|null
     */
    public static function apiShopBody($body, $type, $url)
    {
        $imageList = self::bodyImageArray($body);

        if ($imageList) {
            $patterns       = [];
            $replacements   = [];
            foreach ($imageList as $value) {
                if (stripos($value, 'http') === false) {
                    $imageL = self::shopImageOss($value, $type);
                    if ($imageL == $value) $imageL = self::shopImageSpeed($value, $type);
                    if ($imageL == $value) $imageL = $url . $value;

                    $replacements[] = $imageL;
                    $patterns[] = "/" . preg_replace("/\//i","\/", $value) . "/";
                }
            }
            if (!empty($replacements)) return preg_replace($patterns, $replacements, $body);
        }

        return $body;
    }

    /**
     * 用于后台商品分类列表
     * @param $category
     * @param int $topId
     * @param string $topIdName
     * @param string $idName
     * @param int $level
     * @param string $levelCode
     * @return array
     */
    public static function adminGoodsClass($category, int $topId=0 , string $topIdName='getClassTopId', string $idName='getClassId', int $level = 0, string $levelCode = 'getClassPath')
    {
        static $array = [];
        foreach ($category as $value) {
            if($value[0]->$topIdName() == $topId) {
                if($level > 0 && substr_count($value[0]->$levelCode(), ',') >= $level) continue;

                $array[] = $value;
                self::adminGoodsClass($category, $value[0]->$idName(), $topIdName, $idName, $level, $levelCode);
            }
        }

        return $array;
    }

    /**
     * 输出无限分类
     * @param $category
     * @param int $topId
     * @param string $topIdName
     * @param string $idName
     * @param int $level            //输出层级，0 输出所有，1 输出第一层级
     * @param string $levelCode     //当 $level 大于0时，使用 $levelCode
     * @return array
     */
    public static function classOptions($category, int $topId=0 , string $topIdName='getClassTopId', string $idName='getClassId', int $level = 0, string $levelCode = 'getClassPath')
    {
        static $array = [];
        foreach ($category as $value) {
            if($value->$topIdName() == $topId) {
                if($level > 0 && substr_count($value->$levelCode(), ',') >= $level) continue;

                $array[] = $value;
                self::classOptions($category, $value->$idName(), $topIdName, $idName, $level, $levelCode);
            }
        }

        return $array;
    }

    /**
     * 获取前台默认模板对应编码名称（用于后台） 如 mobile-default
     * @param string $templateTypeName
     * @return string|string[]
     */
    public static function getDefaultTemplateCode(string $templateTypeName = 'mobileTemplate')
    {
       return str_replace('/', '-', self::configValue($templateTypeName, 'template'));
    }

    /**
     * 获取前台默认模板不同标记的数组信息
     * @param $key
     * @param string $templateTypeName
     * @return mixed|null
     */
    public static function getDefaultTemplateTag($key, string $templateTypeName = 'mobileTemplate')
    {
        $templateIniFile = 'module/Shop/view/'.self::configValue($templateTypeName, 'template').'/shop/template.ini';
        $templateConfig = file_exists($templateIniFile) ? Factory::fromFile($templateIniFile) : [];

        return !empty($key) ? (isset($templateConfig[$key]) ? $templateConfig[$key] : null) : $templateConfig;
    }

    /**
     * 获取默认前台模板（主要用于前台）
     * template.php 中的 displayType 分为 auto 自动识别 ， pc 电脑端 ， mobile 手机端
     * @return array|mixed
     */
    public static function getShopDefaultTemplate()
    {
        $template   = self::readConfigFile('template');
        $displayType= $template['displayType'];

        if ($displayType == 'auto') return self::isMobile() ? (empty($template['mobileTemplate']) ? $template['pcTemplate'] : $template['mobileTemplate']) : (empty($template['pcTemplate']) ? $template['mobileTemplate'] : $template['pcTemplate']);

        return $template[$displayType.'Template'];
    }

    /**
     * 获取国际电话区号
     * @param $areaCode
     * @return int
     */
    public static function areaPhoneCode($areaCode)
    {
        return PhoneNumberUtil::getInstance()->getCountryCodeForRegion($areaCode);
    }

    /**
     * 获取国际电话区号数组
     * @return array
     */
    public static function getPhoneArea()
    {
        $areaList = self::readConfigFile('phoneArea');
        $areaArray= [];
        if(count($areaList['list']) == 1) $areaArray[0] = $areaList['default'];
        else {
            foreach ($areaList['list'] as $key => $value) {
                $areaArray[$key] = $value['areaName'];
            }
            return ['default' => $areaList['default']['areaCode'], 'list' => $areaArray];
        }

        return $areaArray;
    }

    /**
     * 校验电话号码是否正确（没有用laminas自带的号码校验组件，不够准确）
     * @param $phoneNumber
     * @param $areaCode
     * @return bool
     */
    public static function checkPhoneNumber($phoneNumber, $areaCode)
    {
        $phoneUtil = PhoneNumberUtil::getInstance();
        //宽松模式
        //return $phoneUtil->isPossibleNumber($phoneNumber, $areaCode);

        //严格模式
        try {
            $swissNumberProto = $phoneUtil->parse($phoneNumber, $areaCode);
        } catch (NumberParseException $e) {
            return false;
        }
        return $phoneUtil->isValidNumber($swissNumberProto);
    }

    /**
     * 对开启等级积分客户组的客户进行判断，如果后台设置为等级积分开启的客户组，同时该客户积分不够，则自动恢复为默认客户组
     * @param $userGroupId
     * @param $userGroupName
     * @param $integralType2Num
     * @return array
     */
    public static function checkIntegralUserGroup($userGroupId, $userGroupName, $integralType2Num)
    {
        $userGroup = self::readConfigFile('userGroup');
        foreach ($userGroup as $groupValue) {
            if ($groupValue['integralState'] == 1 && $integralType2Num >= $groupValue['integralStart'] && $integralType2Num <= $groupValue['integralEnd']) return ['userGroupId' => $groupValue['userGroupId'], 'userGroupName' => $groupValue['userGroupName']];
        }

        if ($userGroup[$userGroupId]['integralState'] == 0) return ['userGroupId' => $userGroupId, 'userGroupName' => $userGroupName];

        $defaultGroupId = self::configValue('default_user_group_id', 'customer');
        if ($defaultGroupId == $userGroupId) return ['userGroupId' => $userGroupId, 'userGroupName' => $userGroupName];

        return ['userGroupId' => $defaultGroupId, 'userGroupName' => $userGroup[$defaultGroupId]['userGroupName']];
    }

    /**
     * 获取支付列表
     * @param bool $state 是否只显示启用的支付方式
     * @param string $onlinePayment 是否是在线支付，true 是，false 不是
     * @param string $currencyCode 货币code
     * @param array $excludePay 需要排除一些支付显示
     * @param array|bool[] $checkArray 判断是否需要进行检测，默认是检测
     * @return array
     */
    public static function paymentList(bool $state = false, string $onlinePayment = '', string $currencyCode = '', array $excludePay = [], array $checkArray = ['wechat' => true, 'alipay' => true, 'mobile' => true])
    {
        $isWechat       = self::isWeixin();//是否在微信内
        $isMobile       = self::isMobile();//是否为移动端
        $isAlipay       = self::isAlipay();//是否为支付宝

        $paymentArray   = [];
        $filePath       = 'data/moduleData/Payment/';
        if(is_dir($filePath)) {
            $dh = scandir($filePath);
            foreach ($dh as $fileName) {
                if (!in_array($fileName, ['.', '..', '.DS_Store']) && stripos($fileName, '.php') !== false) {
                    $paymentInfo = include($filePath . basename($fileName));
                    //开启显示启用的支付方式，一般用于前台
                    if ($state) {
                        if ($paymentInfo['paymentState']['checked'] != 1) continue;

                        if (!$isMobile && !$isWechat) {//PC端
                            if (isset($paymentInfo['paymentShow']) && (empty($paymentInfo['paymentShow']['checked']) || !in_array('pc', $paymentInfo['paymentShow']['checked']))) continue;//pc端不显示
                            if (isset($paymentInfo['paymentPlatform']) && (empty($paymentInfo['paymentPlatform']['checked']) || !in_array('scan', $paymentInfo['paymentPlatform']['checked']))) continue;//如有扫码限制，未设置则不显示
                        } else {
                            if (isset($paymentInfo['paymentShow']) && (empty($paymentInfo['paymentShow']['checked']) || !in_array('phone', $paymentInfo['paymentShow']['checked']))) continue;//手机端端不显示
                            if ($isWechat && $checkArray['wechat']) {//微信内
                                if ($paymentInfo['editAction'] == 'Alipay') continue;//支付宝不显示
                                if (isset($paymentInfo['paymentPlatform']) && (empty($paymentInfo['paymentPlatform']['checked']) || !in_array('wechat', $paymentInfo['paymentPlatform']['checked']))) continue;//如有微信端限制，未设置则不显示
                            }
                            if ($isAlipay && $checkArray['alipay']) {//支付宝内
                                if ($paymentInfo['editAction'] == 'Wxpay') continue;//微信支付不显示
                                if (isset($paymentInfo['paymentPlatform']) && (empty($paymentInfo['paymentPlatform']['checked']) || !in_array('alipay', $paymentInfo['paymentPlatform']['checked']))) continue;//如有支付宝端限制，未设置则不显示
                            }
                            if ($isMobile && $checkArray['mobile'] && !$isWechat && !$isAlipay) {//移动端
                                if (isset($paymentInfo['paymentPlatform']) && (empty($paymentInfo['paymentPlatform']['checked']) || !in_array('h5', $paymentInfo['paymentPlatform']['checked']))) continue;//如有H5限制，未设置则不显示
                            }
                        }
                    }
                    //如果排除支付数组不为空，则进行判断处理，排除掉无需显示的支付方式
                    if (!empty($excludePay) && in_array($paymentInfo['editAction'], $excludePay)) continue;
                    //过滤，在线支付和非在线支付
                    if (!empty($onlinePayment) && $paymentInfo['onlinePayment']['content'] != $onlinePayment) continue;
                    //如果有货币判断则进行货币判断
                    if (!empty($currencyCode) && $paymentInfo['editAction'] != 'BalancePay' && (empty($paymentInfo['paymentCurrency']['checked']) || !in_array($currencyCode, $paymentInfo['paymentCurrency']['checked']))) continue;

                    $paymentArray[] = $paymentInfo;
                }
            }
        }

        usort($paymentArray, function ($a, $b) {
            if($a['paymentSort']['content'] == $b['paymentSort']['content']) {
                return 0;
            }
            return ($a['paymentSort']['content'] < $b['paymentSort']['content']) ? -1 : 1;
        });

        return $paymentArray;
    }

    /**
     * 判断前台是否开启在线支付
     * @return bool
     */
    public static function onlinePaymentState(): bool
    {
        $onlinePayment = Common::paymentList(true, 'true');
        if (!empty($onlinePayment)) return true;

        return false;
    }

    /**
     * 获取支付方式的配置信息
     * @param $configFile
     * @return array|mixed
     */
    public static function getPaymentConfig($configFile)
    {
        $config     = [];
        $configFile = 'data/moduleData/Payment/' . ucfirst(basename($configFile)) . '.php';

        if(file_exists($configFile)) $config = include $configFile;

        return $config;
    }

    /**
     * 调用支付方式
     * @param $serviceName
     * @return mixed
     */
    public static function getPaymentService($serviceName)
    {
        $serviceName    = 'Admin\\Service\\Payment\\' . ucfirst(basename($serviceName)) . 'Service';
        return new $serviceName();
    }

    /**
     * 判断是否为移动端
     * @return bool
     */
    public static function isMobile() {
        // 如果有HTTP_X_WAP_PROFILE则一定是移动设备
        if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
            return true;
        }
        // 如果via信息含有wap则一定是移动设备,部分服务商会屏蔽该信息
        if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], "wap")) {
            // 找不到为false,否则为true
            return true;
        }
        //判断手机发送的客户端标志,兼容性有待提高。其中'MicroMessenger'是电脑微信
        if (isset($_SERVER['HTTP_USER_AGENT'])) {
            $clientKeywords = [
                'nokia',
                'sony',
                'ericsson',
                'mot',
                'samsung',
                'htc',
                'sgh',
                'lg',
                'sharp',
                'sie-',
                'philips',
                'panasonic',
                'alcatel',
                'lenovo',
                'iphone',
                'ipod',
                'blackberry',
                'meizu',
                'android',
                'netfront',
                'symbian',
                'ucweb',
                'windowsce',
                'palm',
                'operamini',
                'operamobi',
                'openwave',
                'nexusone',
                'cldc',
                'midp',
                'wap',
                'mobile',
                'MicroMessenger'
            ];
            // 从HTTP_USER_AGENT中查找手机浏览器的关键字
            if (preg_match("/(" . implode('|', $clientKeywords) . ")/i", strtolower($_SERVER['HTTP_USER_AGENT']))) {
                return true;
            }
        }
        // 协议法，因为有可能不准确，放到最后判断
        if (isset ($_SERVER['HTTP_ACCEPT'])) {
            // 如果只支持wml并且不支持html那一定是移动设备
            // 如果支持wml和html但是wml在html之前则是移动设备
            if ((strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') !== false) && (strpos($_SERVER['HTTP_ACCEPT'], 'text/html') === false || (strpos($_SERVER['HTTP_ACCEPT'], 'vnd.wap.wml') < strpos($_SERVER['HTTP_ACCEPT'], 'text/html')))) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否为微信端
     * @return bool
     */
    public static function isWeixin() {
        return strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false;
    }

    /**
     * 判断是否为支付宝端
     * @return bool
     */
    public static function isAlipay()
    {
        return strpos($_SERVER['HTTP_USER_AGENT'], 'Alipay') !== false;
    }

    /**
     * 将字符串中间的内容用星号代替，一般用于隐藏会员名字
     * @param $strBody
     * @return string
     */
    public static function stringHide($strBody)
    {
        $str      = mb_strlen($strBody, 'utf-8');
        $firstStr = mb_substr($strBody, 0, 1, 'utf-8');
        $lastStr  = mb_substr($strBody, -1, 1, 'utf-8');
        return $str == 2 ? $firstStr . str_repeat('*', $str - 1) : $firstStr . str_repeat("*", $str - 2) . $lastStr;
    }

    /**
     * 字符截取方法
     * @param string $str   要截取的字符串
     * @param int $length   需要截取的长度，0为不截取
     * @param bool $append  是否显示省略号，默认显示
     * @return false|string
     */
    public static function shopCutStr(string $str, int $length=0, bool $append=true)
    {
        $str = trim($str);
        $strLength = strlen($str);

        if ($length == 0 || $length >= $strLength) {
            return $str;
        } elseif ($length < 0) {
            $length = $strLength + $length;
            if ($length < 0) {
                $length = $strLength;
            }
        }
        if (function_exists('mb_substr')) {
            $newStr = mb_substr($str, 0, $length, 'utf-8');
        } elseif (function_exists('iconv_substr')) {
            $newStr = iconv_substr($str, 0, $length, 'utf-8');
        } else {
            $newStr = substr($str, 0, $length);
        }
        if ($append && $str != $newStr){
            $newStr .= '...';
        }
        return $newStr;
    }

    /**
     * 固定长度分行处理
     * @param string $str   字符串
     * @param int $row      行数
     * @param int $number   几个字符为一行
     * @param bool $suffix  截取是否显示省略号
     * @return array
     */
    public static function cnRowSubstr(string $str, int $row = 1, int $number = 10, bool $suffix = false)
    {
        $result = [];
        for ($r=1;$r<=$row;$r++){
            $result[$r] = '';
        }

        $str = trim($str);
        if(!$str) return $result;

        $theStrLen = strlen($str);

        //每行实际字节长度
        $oneRowNum = $number * 3;
        for($r=1;$r<=$row;$r++){
            if($r == $row and $theStrLen > $r * $oneRowNum and $suffix){
                $result[$r] = self::mgCnSubstr($str,$oneRowNum-6,($r-1)* $oneRowNum).'...';
            }else{
                $result[$r] = self::mgCnSubstr($str,$oneRowNum,($r-1)* $oneRowNum);
            }
            if($theStrLen < $r * $oneRowNum) break;
        }

        return $result;
    }
    private static function mgCnSubstr($str,$len,$start = 0){
        $qStr = '';
        $qStrLen = ($start + $len)>strlen($str) ? strlen($str) : ($start + $len);

        //如果start不为起始位置，若起始位置为乱码就按照UTF-8编码获取新start
        if($start and json_encode(substr($str,$start,1)) === false){
            for($a=0;$a<3;$a++){
                $new_start = $start + $a;
                $m_str = substr($str,$new_start,3);
                if(json_encode($m_str) !== false) {
                    $start = $new_start;
                    break;
                }
            }
        }

        //切取内容
        for($i=$start; $i<$qStrLen; $i++){
            //ord()函数取得substr()的第一个字符的ASCII码，如果大于0xa0的话则是中文字符
            if(ord(substr($str,$i,1))>0xa0){
                $qStr .= substr($str,$i,3);
                $i+=2;
            }else{
                $qStr .= substr($str,$i,1);
            }
        }
        return $qStr;
    }

    /**
     * 微信分享公众号信息
     * @param $shareUrl
     * @return array|string
     */
    public static function getWxSignPackage($shareUrl)
    {
        $wxPayConfig = self::getPaymentConfig('wxpay');
        self::$commonData['wxAppId']        = $wxPayConfig['paymentAppId']['content'];
        self::$commonData['wxAppSecret']    = $wxPayConfig['paymentAppSecret']['content'];

        if (empty(self::$commonData['wxAppId']) || empty(self::$commonData['wxAppSecret'])) return 'false';

        $ticket     = self::getJsApiTicket();
        $timeStamp  = time();
        $nonceStr   = Rand::getString(16, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');

        $string     = "jsapi_ticket=$ticket&noncestr=$nonceStr&timestamp=$timeStamp&url=$shareUrl";
        $signature = sha1($string);

        return [
            "appId"     => self::$commonData['wxAppId'],
            "nonceStr"  => $nonceStr,
            "timeStamp" => $timeStamp,
            "url"       => $shareUrl,
            "signature" => $signature,
            "rawString" => $string
        ];
    }
    public static function getJsApiTicket()
    {
        $nowTime        = time();
        $accessTokenFile= 'data/moduleData/User/accessToken.json';
        $data           = Factory::fromFile($accessTokenFile);
        if($data['ticket_expire_time'] < $nowTime) {
            if($data['token_expire_time'] < $nowTime) {
                $token = self::getAccessToken();
                if ($token) {
                    $data['access_token']       = $token;
                    $data['token_expire_time']  = $nowTime + 7000;
                }
            }
            $url  = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=".$data['access_token'];
            $res  = Json::decode(self::httpGet($url));
            if($res->ticket) {
                $data['ticket_expire_time'] = $nowTime + 7000;
                $data['ticket']             = $res->ticket;
                Factory::toFile($accessTokenFile, $data);
            }
        }

        return $data['ticket'];
    }

    /**
     * 获取微信小程序的openid
     * @param $wxData
     * @return mixed
     */
    /**
     * 获取微信小程序的openid 如果 $userInfo 为 true 则返回info信息
     * @param $wxData
     * @param bool $userInfo
     * @return mixed
     */
    public static function getWechatMiniOpenId($wxData, bool $userInfo = false)
    {
        $bizString = self::toUrlParams([
            'appid'     => $wxData['wxMiniId'],
            'secret'    => $wxData['wxMiniSecret'],
            'js_code'   => $wxData['code'],
            'grant_type'=> 'authorization_code'
        ]);
        $res = Json::decode(self::httpGet("https://api.weixin.qq.com/sns/jscode2session?".$bizString));
        return $userInfo ? $res : $res->openid;
    }

    /**
     * 获取微信公众号的openid
     * @param $wxData
     * @return mixed
     */
    public static function getWechatOpenId($wxData)
    {
        if (!isset($_GET['code'])) {
            if (isset($wxData['toGetUrl'])) {
                header("Location: ".$wxData['toGetUrl']."?type=login&appId=".$wxData['wxAppId']."&toUrl=".$wxData['redirectUrl']);
                exit();
            }

            $bizString = self::toUrlParams([
                'appid'         => $wxData['wxAppId'],
                'redirect_uri'  => $wxData['redirectUrl'],
                'response_type' => 'code',
                'scope'         => 'snsapi_base',
                'state'         => 'STATE#wechat_redirect'
            ]);
            header("Location: https://open.weixin.qq.com/connect/oauth2/authorize?".$bizString);
            exit();
        } else {
            $bizString = self::toUrlParams([
                'appid'     => $wxData['wxAppId'],
                'secret'    => $wxData['wxAppSecret'],
                'code'      => $_GET['code'],
                'grant_type'=> 'authorization_code'
            ]);
            $res = Json::decode(self::httpGet("https://api.weixin.qq.com/sns/oauth2/access_token?".$bizString));
            return $res->openid;
        }
    }

    /**
     * 获取Token
     * @param string $wxAppId
     * @param string $wxAppSecret
     * @return false
     */
    public static function getAccessToken(string $wxAppId = '', string $wxAppSecret = '')
    {
        if (empty($wxAppId) && empty($wxAppSecret)) {
            $wxAppId        = self::$commonData['wxAppId'];
            $wxAppSecret    = self::$commonData['wxAppSecret'];
        }

        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$wxAppId."&secret=".$wxAppSecret;
        $res = Json::decode(self::httpGet($url));
        if($res->access_token) {
            return $res->access_token;
        }
        return false;
    }
    public static function httpGet($url)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 500);
        curl_setopt($curl, CURLOPT_URL, $url);

        $res = curl_exec($curl);
        curl_close($curl);

        return $res;
    }
    public static function toUrlParams($params, $filter = 'sign')
    {
        $buff = '';
        foreach ($params as $key => $val) {
            if ($key != $filter) $buff .= $key . '=' . urlencode($val) . '&';
        }
        return trim($buff, '&');
    }

    /**
     * 获取内容中的图片信息
     * @param $body
     * @return array|null
     */
    public static function bodyImageArray($body)
    {
        $imageArray = [];
        preg_match_all("/<img.*?src=[\'|\"](.*?(?:[.gif|.jpg|.jpeg|.png|.bmp]))[\'|\"].*?[\/]?>/", $body, $imageArray);
        if (is_array($imageArray[1]) && !empty($imageArray[1])) return $imageArray[1];

        return null;
    }

    /**
     * 有效时间检查
     * @param $startTime
     * @param $endTime
     * @return bool
     */
    public static function checkTime($startTime, $endTime)
    {
        if ($startTime == 0 && $endTime == 0) return true;

        if($startTime > 0 && $endTime > 0 && $startTime > $endTime) return false;
        if($startTime > 0 && $startTime > time()) return false;
        if($endTime > 0 && $endTime < time()) return false;

        return true;
    }

    /**
     * 检查会员，会员组
     * @param $userGroupId
     * @param $userType
     * @param $userBody
     * @return bool
     */
    public static function checkUser($userGroupId, $userType, $userBody)
    {
        if($userType == 'allUser') return true;
        if($userType == 'userGroup' && !empty($userBody) && in_array($userGroupId, $userBody)) return true;

        return false;
    }

    /**
     * 检查商品，商品分类、商品品牌
     * @param $goodsClassId
     * @param $goodsType
     * @param $goodsBody
     * @param int $goodsBrandId
     * @return bool
     */
    public static function checkGoods($goodsClassId, $goodsType, $goodsBody, int $goodsBrandId = 0)
    {
        if($goodsType == 'allGoods') return true;

        if(empty($goodsBody)) return false;
        if($goodsType == 'goodsClass' && in_array($goodsClassId, $goodsBody)) return true;
        if($goodsType == 'goodsBrand' && $goodsBrandId > 0 && in_array($goodsBrandId, $goodsBody)) return true;

        return false;
    }

    /**
     * 列出目录下的所有文件，包括子目录文件,不包含sql目录
     * @param $dirName
     * @return array
     */
    public static function getAllFile($dirName)
    {
        $dirName    = str_replace('..', '', rtrim($dirName, '/\\'));
        $fileArray  = [];
        if (is_dir($dirName)) {
            $dh = scandir($dirName);
            foreach ($dh as $file) {
                if (!in_array($file, ['.', '..', 'sql', '.DS_Store'])) {
                    $path = $dirName . DIRECTORY_SEPARATOR . $file;
                    if (!is_dir($path)) $fileArray[] = $path;
                    $fileArray = array_merge($fileArray, self::getAllFile($path));
                }
            }
        }
        return $fileArray;
    }

    /**
     * 删除目录及目录下的文件
     * @param $dirName
     * @param bool $delDir
     */
    public static function deleteDirAndFile($dirName, bool $delDir = true)
    {
        $dirName = str_replace('..', '', rtrim($dirName, '/\\'));
        if (is_dir($dirName)) {
            $dh = scandir($dirName);
            foreach ($dh as $file) {
                if (!in_array($file, ['.', '..', '.DS_Store'])) {
                    $fullPath = $dirName . DIRECTORY_SEPARATOR . $file;
                    if (!is_dir($fullPath)) @unlink($fullPath);
                    else self::deleteDirAndFile($fullPath);
                }
            }
            if ($delDir) @rmdir($dirName);
        }
    }

    /**
     * 解压压缩包
     * @param $packageFile
     * @param $toPath
     */
    public static function decompressPackage($packageFile, $toPath)
    {
        $ex = substr($packageFile, -4);
        switch ($ex) {
            case '.zip':
            case '.ZIP':
            $decompress = new Decompress(['adapter' => 'Zip', 'options' => ['target' => $toPath]]);
            $decompress->filter($packageFile);
                break;
            case 'r.gz':
                $decompress = new \PharData($packageFile);
                $decompress->extractTo($toPath, null, true);
                break;
        }
    }

    /**
     * 检查某个目录的所有文件，生成copy数组文件和删除数组文件，目前用于插件内需复制的目录
     * 用法如 Common::scanDirFileCopyArray('PluginModuleManagement/copyFile/public', '/copyFile/public', 'public');
     * @param $path
     * @param $copyPath
     * @param $copyToPath
     * @return void
     */
    public static function scanDirFileCopyArray($path, $copyPath, $copyToPath)
    {
        $fileArray  = self::getAllFile('module/Plugin/' . $path);
        $copyArray  = [];
        $delArray   = [];
        if (is_array($fileArray) && !empty($fileArray)) {
            foreach ($fileArray as $file) {
                $file       = str_replace(['module/Plugin/' . $path, '\\'], ['', '/'], $file);
                $copyArray[]= ['copy' => $copyPath . $file, 'copyTo' => $copyToPath . $file];
                $delArray[] = $copyToPath . $file;
            }
        }

        $writeFile = new PhpArray();
        $writeFile->setUseBracketArraySyntax(true);

        $writeFile->toFile('module/Plugin/' . $path . '/../copyFile.php', $copyArray);
        $writeFile->toFile('module/Plugin/' . $path . '/../delFile.php', $delArray);
    }

    /**
     * 图片删除
     * @param $image
     * @return bool
     */
    public static function deleteImages($image)
    {
        if(empty($image)) return false;
        $imageArray = is_array($image) ? $image : [$image];

        foreach ($imageArray as $imageValue) {
            if (stripos($imageValue, 'http') !== false) continue;

            $imagePath = dirname($imageValue);
            $imagePath = empty($imagePath) ? '' : str_replace('.', '', $imagePath) . '/';
            $imageName = basename($imageValue);
            $imageFile = getcwd() . '/public/' . $imagePath . $imageName;
            if(file_exists($imageFile) && !is_dir($imageFile)) unlink($imageFile);
        }
        return true;
    }

    /**
     * 高精度计算
     * @param $m
     * @param $n
     * @param string $type
     * @param int $scale
     * @return string|null
     */
    public static function calculation($m, $n, string $type, int $scale = 0)
    {
        $num = 0;
        switch ($type) {
            case 'add'://加
            case '+':
                $num = bcadd($m, $n, $scale);
                break;
            case 'sub'://减
            case '-':
                $num = bcsub($m, $n, $scale);
                break;
            case 'mul'://乘
            case '*':
                $num = bcmul($m, $n, $scale);
                break;
            case 'div'://除
            case '/':
                $num = bcdiv($m, $n, $scale);
                break;
        }
        return $num;
    }
}